package jamirr;

import java.util.*;

final class Utils {

    /**
     * Simple Annotation name used for nullable.
     */
    public static final String NULLABLE_ANNOTATION = "jakarta.annotation.Nullable";

    /**
     * Simple Annotation name used for non-null.
     */
    public static final String NON_NULL_ANNOTATION = "jakarta.annotation.Nonnull";

    public static final String[] EMPTY_STRING_ARRAY = new String[0];
    public static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];

    public static String uncapitalize(String name) {
        if (name == null) {
            return null;
        }
        int length = name.length();
        if (length == 0) {
            return name;
        }
        // Decapitalizes the first character if a lower case
        // letter is found within 2 characters after the first
        // Abc -> abc
        // AB  -> AB
        // ABC -> ABC
        // ABc -> aBc
        boolean firstUpper = Character.isUpperCase(name.charAt(0));
        if (firstUpper) {
            if (length == 1) {
                return Character.toString(Character.toLowerCase(name.charAt(0)));
            }
            for (int i = 1; i < Math.min(length, 3); i++) {
                if (!Character.isUpperCase(name.charAt(i))) {
                    char[] chars = name.toCharArray();
                    chars[0] = Character.toLowerCase(chars[0]);
                    return new String(chars);
                }
            }
        }

        return name;
    }


    @SafeVarargs
    public static <T> Set<T> setOf(T... objects) {
        if (objects == null || objects.length == 0) {
            return new HashSet<>(0);
        }
        return new HashSet<>(Arrays.asList(objects));
    }

    public static <K, V> LinkedHashMap<K, V> newLinkedHashMap(int size) {
        return new LinkedHashMap<>(calculateHashSetSize(size));
    }

    public static int hash(Object o1, Object o2) {
        int result = 1;
        result = 31 * result + (o1 == null ? 0 : o1.hashCode());
        result = 31 * result + (o2 == null ? 0 : o2.hashCode());
        return result;
    }

    public static int hash(Object o1, Object o2, Object o3) {
        int result = hash(o1, o2);
        result = 31 * result + (o3 == null ? 0 : o3.hashCode());
        return result;
    }

    private static int calculateHashSetSize(int size) {
        // Based on the calculation in new HashSet(Collection)
        return Math.max((int) (size / .75f) + 1, 16);
    }

    private static final Map<Class<?>, Class<?>> PRIMITIVES_TO_WRAPPERS;

    static {
        LinkedHashMap<Class<?>, Class<?>> m = new LinkedHashMap<>();
        m.put(boolean.class, Boolean.class);
        m.put(byte.class, Byte.class);
        m.put(char.class, Character.class);
        m.put(double.class, Double.class);
        m.put(float.class, Float.class);
        m.put(int.class, Integer.class);
        m.put(long.class, Long.class);
        m.put(short.class, Short.class);
        m.put(void.class, Void.class);
        PRIMITIVES_TO_WRAPPERS = Collections.unmodifiableMap(m);
    }

    public static Class<?> getWrapperType(Class<?> primitiveType) {
        if (primitiveType.isPrimitive()) {
            return PRIMITIVES_TO_WRAPPERS.get(primitiveType);
        }
        return primitiveType;
    }

}
